﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XChipUtils
{
    public  class BitsHelp : IBitsHelper
    {
        /// <summary>
        /// 从十六进制字符串中根据指定的位范围获取位值
        /// </summary>
        public ulong GetBits(string str, string num)
        {
            var temp = Convert.ToUInt32(num, 16);
            ulong rtemp = 0;
            // 根据位范围解析并获取相应的位值
            switch (str)
            {
                case "[31:0]":
                    rtemp = (ulong)temp;
                    break;
                case "[31:9]":
                    rtemp = (ulong)temp >> 9;
                    break;
                case "[8]":
                    rtemp = (ulong)temp >> 8 & 0x01;
                    break;
                case "[7:1]":
                    rtemp = (ulong)temp >> 1 & 0x7f;
                    break;
                case "[0]":
                    rtemp = (ulong)temp & 0x01;
                    break;
                case "[31:1]":
                    rtemp = (ulong)temp >> 1;
                    break;
                case "[31]":
                    rtemp = (ulong)temp >> 31;
                    break;
                case "[30]":
                    rtemp = (ulong)temp >> 30 & 0x01;
                    break;
                case "[29]":
                    rtemp = (ulong)temp >> 29 & 0x01;
                    break;
                case "[28]":
                    rtemp = (ulong)temp >> 28 & 0x01;
                    break;
                case "[27]":
                    rtemp = (ulong)temp >> 27 & 0x01;
                    break;
                case "[26]":
                    rtemp = (ulong)temp >> 26 & 0x01;
                    break;
                case "[25]":
                    rtemp = (ulong)temp >> 25 & 0x01;
                    break;
                case "[24]":
                    rtemp = (ulong)temp >> 24 & 0x01;
                    break;
                case "[23]":
                    rtemp = (ulong)temp >> 23 & 0x01;
                    break;
                case "[22]":
                    rtemp = (ulong)temp >> 22 & 0x01;
                    break;
                case "[21]":
                    rtemp = (ulong)temp >> 21 & 0x01;
                    break;
                case "[20]":
                    rtemp = (ulong)temp >> 20 & 0x01;
                    break;
                case "[19]":
                    rtemp = (ulong)temp >> 19 & 0x01;
                    break;
                case "[18]":
                    rtemp = (ulong)temp >> 18 & 0x01;
                    break;
                case "[17]":
                    rtemp = (ulong)temp >> 17 & 0x01;
                    break;
                case "[16]":
                    rtemp = (ulong)temp >> 16 & 0x01;
                    break;
                case "[15]":
                    rtemp = (ulong)temp >> 15 & 0x01;
                    break;
                case "[14]":
                    rtemp = (ulong)temp >> 14 & 0x01;
                    break;
                case "[13]":
                    rtemp = (ulong)temp >> 13 & 0x01;
                    break;
                case "[12]":
                    rtemp = (ulong)temp >> 12 & 0x01;
                    break;
                case "[11]":
                    rtemp = (ulong)temp >> 11 & 0x01;
                    break;
                case "[10]":
                    rtemp = (ulong)temp >> 10 & 0x01;
                    break;
                case "[9]":
                    rtemp = (ulong)temp >> 9 & 0x01;
                    break;

                case "[7]":
                    rtemp = (ulong)temp >> 7 & 0x01;
                    break;
                case "[6]":
                    rtemp = (ulong)temp >> 6 & 0x01;
                    break;
                case "[5]":
                    rtemp = (ulong)temp >> 5 & 0x01;
                    break;
                case "[4]":
                    rtemp = (ulong)temp >> 4 & 0x01;
                    break;
                case "[4:2]":
                    rtemp = (ulong)temp >> 2 & 0x07;
                    break;
                case "[3]":
                    rtemp = (ulong)temp >> 3 & 0x01;
                    break;
                case "[2]":
                    rtemp = (ulong)temp >> 2 & 0x01;
                    break;
                case "[1]":
                    rtemp = (ulong)temp >> 1 & 0x01;
                    break;
                case "[23:16]":
                    rtemp = (ulong)temp >> 16 & 0xff;
                    break;
                case "[15:12]":
                    rtemp = (ulong)temp >> 12 & 0x0f;
                    break;
                case "[7:0]":
                    rtemp = (ulong)temp & 0xff;
                    break;
                case "[31:27]":
                    rtemp = (ulong)temp >> 27;
                    break;
                case "[15:11]":
                    rtemp = (ulong)temp >> 11 & 0x1f;
                    break;
                case "[31:17]":
                    rtemp = (ulong)temp >> 17;
                    break;
                case "[31:22]":
                    rtemp = (ulong)temp >> 22;
                    break;
                case "[21:16]":
                    rtemp = (ulong)temp >> 16 & 0x3f;
                    break;
                case "[15:14]":
                    rtemp = (ulong)temp >> 14 & 0x03;
                    break;
                case "[13:8]":
                    rtemp = (ulong)temp >> 8 & 0x3f;
                    break;
                case "[7:4]":
                    rtemp = (ulong)temp >> 4 & 0x0f;
                    break;
                case "[3:2]":
                    rtemp = (ulong)temp >> 2 & 0x03;
                    break;
                case "[6:4]":
                    rtemp = (ulong)temp >> 4 & 0x07;
                    break;
                case "[31:2]":
                    rtemp = (ulong)temp >> 2;
                    break;
                case "[28:26]":
                    rtemp = (ulong)temp >> 26 & 0x07;
                    break;
                case "[23:12]":
                    rtemp = (ulong)temp >> 12 & 0x7ff;
                    break;
                case "[11:8]":
                    rtemp = (ulong)temp >> 8 & 0x0f;
                    break;
                case "[5:4]":
                    rtemp = (ulong)temp >> 4 & 0x03;
                    break;
                case "[23:0]":
                    rtemp = (ulong)temp & 0xffffff;
                    break;
                case "[25:16]":
                    rtemp = (ulong)temp >> 16 & 0x3ff;
                    break;
                case "[15:8]":
                    rtemp = (ulong)temp >> 8 & 0xff;
                    break;
                case "[9:0]":
                    rtemp = (ulong)temp & 0x3ff;
                    break;
                case "[26:25]":
                    rtemp = (ulong)temp >> 25 & 0x03;
                    break;
                case "[30:24]":
                    rtemp = (ulong)temp >> 24 & 0x7f;
                    break;
                case "[22:16]":
                    rtemp = (ulong)temp >> 16 & 0x7f;
                    break;
                case "[31:28]":
                    rtemp = (ulong)temp >> 28;
                    break;
                case "[27:24]":
                    rtemp = (ulong)temp >> 24 & 0x0f;
                    break;
                case "[19:16]":
                    rtemp = (ulong)temp >> 16 & 0x0f;
                    break;
                case "[31:16]":
                    rtemp = (ulong)temp >> 16;
                    break;
                case "[15:13]":
                    rtemp = (ulong)temp >> 13 & 0x07;
                    break;
                case "[12:8]":
                    rtemp = (ulong)temp >> 8 & 0x1f;
                    break;
                case "[7:6]":
                    rtemp = (ulong)temp >> 6 & 0x03;
                    break;
                case "[1:0]":
                    rtemp = (ulong)temp & 0x03;
                    break;
                case "[20:8]":
                    rtemp = (ulong)temp >> 8 & 0x1fff;
                    break;
                case "[30:28]":
                    rtemp = (ulong)temp >> 28 & 0x07;
                    break;
                case "[26:24]":
                    rtemp = (ulong)temp >> 24 & 0x07;
                    break;
                case "[22:20]":
                    rtemp = (ulong)temp >> 20 & 0x07;
                    break;
                case "[18:16]":
                    rtemp = (ulong)temp >> 16 & 0x07;
                    break;
                case "[14:12]":
                    rtemp = (ulong)temp >> 12 & 0x07;
                    break;
                case "[10:8]":
                    rtemp = (ulong)temp >> 8 & 0x07;
                    break;
                case "[2:0]":
                    rtemp = (ulong)temp & 0x07;
                    break;
                case "[31:8]":
                    rtemp = (ulong)temp >> 8;
                    break;
                case "[31:24]":
                    rtemp = (ulong)temp >> 24;
                    break;
                case "[31:26]":
                    rtemp = (ulong)temp >> 26;
                    break;
                case "[7:5]":
                    rtemp = (ulong)temp >> 5 & 0x07;
                    break;
                case "[16:0]":
                    rtemp = (ulong)temp & 0x1ffff;
                    break;
                case "[23:20]":
                    rtemp = (ulong)temp >> 20 & 0x0f;
                    break;
                case "[17:16]":
                    rtemp = (ulong)temp >> 16 & 0x03;
                    break;
                case "[15:0]":
                    rtemp = (ulong)temp & 0xffff;
                    break;
                case "[25:24]":
                    rtemp = (ulong)temp >> 24 & 0x03;
                    break;
                case "[7:2]":
                    rtemp = (ulong)temp >> 2 & 0x3f;
                    break;
                case "[7:3]":
                    rtemp = (ulong)temp >> 3 & 0x1f;
                    break;
                case "[3:0]":
                    rtemp = (ulong)temp & 0x0f;
                    break;
                case "[5:3]":
                    rtemp = (ulong)temp >> 3 & 0x07;
                    break;
                case "[6:0]":
                    rtemp = (ulong)temp & 0x7f;
                    break;
                case "[4:0]":
                    rtemp = (ulong)temp & 0x1f;
                    break;
                case "[5:0]":
                    rtemp = (ulong)temp & 0x3f;
                    break;
                default:
                    break;
            }
            return rtemp;
        }

        /// <summary>
        /// 将指定的值设置到指定的十六进制字符串中的位
        /// </summary>
        public ulong SetBitsToUint(string bits, string hex, string val)
        {
            var valTemp = Convert.ToUInt32(val, 16);
            var bitsTemp = bits.Replace("[", "").Replace("]", "").Split(':');
            int min = bitsTemp.Min(c => int.Parse(c));
            return valTemp >> min & Convert.ToUInt32(hex, 16);
        }

        /// <summary>
        /// 获取指定位范围的值并转换为无符号整数
        /// </summary>
        public long GetBitsToUint(string bits, string hex, string val)
        {
            var valTemp = Convert.ToUInt32(val, 16);
            var bitsTemp = bits.Replace("[", "").Replace("]", "").Split(':');
            int min = bitsTemp.Min(c => int.Parse(c));
            return (valTemp >> min) & Convert.ToUInt32(hex, 16);
        }

        /// <summary>
        /// 根据检查标志设置位并返回无符号整数
        /// </summary>
        public ulong SetBitsCheckedToUint(string bits, string hex, string val, bool isCheck)
        {
            var valTemp = Convert.ToUInt32(val, 16);
            var hexTemp = Convert.ToUInt32(hex, 16);
            return isCheck ? (valTemp | hexTemp) : (valTemp & (hexTemp ^ 0xff));
        }

        /// <summary>
        /// 根据位和十六进制字符串的值判断位是否被设置
        /// </summary>
        public long GetBitsCheckedToBool(string bits, string hex, string val)
        {
            var valTemp = Convert.ToUInt32(val, 16);
            var hexTemp = Convert.ToUInt32(hex, 16);
            return ((valTemp & hexTemp) == hexTemp) ? 0 : 1;
        }

        /// <summary>
        /// 根据位范围和位宽生成位掩码
        /// </summary>
        public string GetBitsToMask(string bits, string bitWide, List<string> bList)
        {
            string maskStr = "";
            double bitNo = 2;
            List<string> blArr = new List<string>();
            // 解析 bList，识别位范围
            for (int i = 0; i < bList.Count; i++)
            {
                var blTemp = bList[i].Replace("[", "").Replace("]", "").Split(':');
                blArr.AddRange(blTemp);
            }
            int max = blArr.Max(c => int.Parse(c));
            int min = blArr.Min(c => int.Parse(c));
            bitNo = Math.Ceiling(((max - min) + 1) / 4.0);
            bitNo += (bitNo % 2);
            maskStr = @"[0-9a-fA-F]{1," + $"{(int)bitNo}" + "}";
            return maskStr;
        }
        public  int GetBitsMaxLength(List<string> bList)
        {
            // 解析 bList，找到所有位范围的最小值和最大值
            var bitRanges = bList.Select(br =>
            {
                var parts = br.Trim('[', ']').Split(':');
                int start = int.Parse(parts[0]);
                int end = int.Parse(parts[1]);
                return (start, end);
            }).ToList();

            int minBit = bitRanges.Min(range => range.end);
            int maxBit = bitRanges.Max(range => range.start);

            // 计算需要的十六进制位数（每4位二进制表示一个十六进制字符）
            int bitNo = (int)Math.Ceiling((maxBit - minBit + 1.0) / 4.0);

            // 如果需要的话，将 bitNo 调整为偶数（这一步的逻辑取决于您的具体需求）
            if (bitNo % 2 != 0)
            {
                bitNo++;
            }

            return bitNo;
        }
    }
}

